package com.rq.viewtestapplication;

import android.graphics.Rect;
import android.util.SparseArray;
import android.view.View;

import java.util.HashMap;
import java.util.Map;

public class ViewInfo {
    private float l, t, r, b;
    private View v;
    private final float[] originSize = new float[4];
    private final SparseArray<Rect> history = new SparseArray<>();

    public ViewInfo(View v, float x, float y, int width, int height) {
        this.v = v;
        this.l = (int) x;
        this.t = (int) y;
        this.r = x + width;
        this.b = y + height;
        this.originSize[0] = x;
        this.originSize[1] = y;
        this.originSize[2] = x + width;
        this.originSize[3] = y + height;
        this.setView(x, y, x + width, y + height, false);
    }

    public void reset() {
        this.l = originSize[0];
        this.t = originSize[1];
        this.r = originSize[2];
        this.b = originSize[3];
        this.setView(originSize[0], originSize[1], originSize[2], originSize[3], false);
    }

    public int getLeft() {
        return (int) l;
    }


    public int getTop() {
        return (int) t;
    }

    public int getRight() {
        return (int) r;
    }

    public int getBottom() {
        return (int) b;
    }

    public int getWidth() {
        return (int) (r - l);
    }

    public int getHeight() {
        return (int) (b - t);
    }


    /**
     * update 为修改位置
     */
    public void update() {
        this.l = v.getX();
        this.t = v.getY();
        this.r = v.getX() + v.getWidth();
        this.b = v.getY() + v.getHeight();
        boundCash.put(v.hashCode(), new Rect((int) v.getX(), (int) v.getY(), (int) v.getX() + v.getWidth(), (int) v.getY() + v.getHeight()));
    }

    public View getView() {
        return this.v;
    }

    public final static int SPEED_LIMIT = 500;//贴边速度限制值
    public final static int ALIGNING_MIN = 30;//自动贴边距离限制

    /**
     * 移动并更新视图
     *
     * @param x
     * @param y
     * @param xVelocity
     * @param yVelocity
     */
    public void move(float x, float y, float xVelocity, float yVelocity) {
        LOG.e("ViewInfo.move", "xVelocity:" + xVelocity + " yVelocity:" + yVelocity);
        boolean calc = Math.abs(xVelocity) + Math.abs(yVelocity) < SPEED_LIMIT;
        LOG.e("ViewInfo.move", "calc:" + calc);
        setView(getLeft() + x, getTop() + y, getLeft() + x + getWidth(), getTop() + y + getHeight(), calc);
    }

    public void move(float x, float y) {
        setView(x + getLeft(), y + getTop(), x + getLeft() + getWidth(), y + getTop() + getHeight(), false);
    }

    public boolean isFocus(View child) {
        return this.v == child;
    }

    private static boolean autoAligning = true;
    private static Map<Integer, Rect> boundCash = new HashMap<>();

    public static void setAutoAligning(boolean open) {
        ViewInfo.autoAligning = open;
    }

    public void changeLTRB(int l, int t, int r, int b) {
        setView(l, t, r, b, false);
    }

    /**
     * 自动计算并
     *
     * @param l
     * @param t
     * @param r
     * @param b
     * @param calculateWelt 是否开启 自动对齐/贴边效果
     */
    private void setView(float l, float t, float r, float b, boolean calculateWelt) {
        if (autoAligning && calculateWelt) {
            float _l = l;
            float _t = t;
            float _r = r;
            float _b = b;
            float minX = ALIGNING_MIN;
            float minY = ALIGNING_MIN;
            final float width = r - l;
            final float height = b - t;
            for (Integer view : boundCash.keySet()) {
                if (v.hashCode() == view) continue;
                Rect rect = boundCash.get(view);
                if (rect == null) continue;
                if (Math.abs(rect.left - l) < minX) {
                    minX = Math.abs(rect.left - l);
                    _l = rect.left;
                    _r = rect.left + width;
                } else if (Math.abs((rect.left + rect.right) - (l + r)) < minX * 2) {
                    minX = Math.abs((rect.left + rect.right) - (l + r)) / 2;
                    _l = (rect.left + rect.right - width) / 2;
                    _r = (rect.left + rect.right + width) / 2;
                } else if (Math.abs(rect.right - r) < minX) {
                    minX = Math.abs(rect.right - r);
                    _l = rect.right - width;
                    _r = rect.right;
                } else if (Math.abs(rect.right - l) < minX) {
                    minX = Math.abs(rect.right - l);
                    _l = rect.right;
                    _r = rect.right + width;
                } else if (Math.abs(rect.left - r) < minX) {
                    minX = Math.abs(rect.left - r);
                    _l = rect.left - width;
                    _r = rect.left;
                }
                if (Math.abs(rect.top - t) < minY) {
                    minY = Math.abs(rect.top - t);
                    _t = rect.top;
                    _b = rect.top + height;
                } else if (Math.abs((rect.bottom + rect.top) - (t + b)) < minY * 2) {
                    minY = Math.abs((rect.bottom + rect.top) - (t + b)) / 2;
                    _t = (rect.bottom + rect.top - height) / 2;
                    _b = (rect.bottom + rect.top + height) / 2;
                } else if (Math.abs(rect.bottom - b) < minY) {
                    minY = Math.abs(rect.bottom - b);
                    _t = rect.bottom - height;
                    _b = rect.bottom;
                } else if (Math.abs(rect.bottom - t) < minY) {
                    minY = Math.abs(rect.bottom - t);
                    _t = rect.bottom;
                    _b = rect.bottom + height;
                } else if (Math.abs(rect.top - b) < minY) {
                    minY = Math.abs(rect.top - b);
                    _t = rect.top - height;
                    _b = rect.top;
                }
            }
            boundCash.put(v.hashCode(), new Rect((int) _l, (int) _t, (int) _r, (int) _b));
            history.put(history.size(), new Rect((int) _l, (int) _t, (int) _r, (int) _b));
            v.layout((int) _l, (int) _t, (int) _r, (int) _b);
        } else {
            boundCash.put(v.hashCode(), new Rect((int) l, (int) t, (int) r, (int) b));
            history.put(history.size(), new Rect((int) l, (int) t, (int) r, (int) b));
            v.layout((int) l, (int) t, (int) r, (int) b);
        }
    }

    public boolean cannotSee() {
        return (r - l) == 0 || (b - t) == 0
                ||
                v.getVisibility() != View.VISIBLE
                ||
                (l > AppUtil.getWidth(v.getContext()) || t > AppUtil.getHeight(v.getContext()) || l + getWidth() < 0 || t + getHeight() < 0)
                ;
    }
}
